package net.sf.ivyide.idea;

import com.intellij.openapi.components.ProjectComponent;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.util.IconLoader;
import com.intellij.openapi.wm.WindowManager;
import net.sf.ivyide.ResolveException;
import org.jetbrains.annotations.NotNull;

import javax.swing.*;

public class IvyProjectComponent implements ProjectComponent, Configurable {

    private static final Logger LOGGER = Logger.getInstance(IvyProjectComponent.class.getName());
    public static final Icon BIG_ICON = IconLoader.getIcon("/logo32.png");


    private static String COMPONENT_NAME = "ivyprojectcomponent";
    private Project m_project;
    private IvyProjectSettings m_settingsCopy;
    private IvyProjectSettings m_settings;
    private IvyDependenciesStep m_testStep;


    public IvyProjectComponent(Project project) {
        m_project = project;
        m_settings = project.getComponent(IvyProjectSettings.class);
        m_settingsCopy = new IvyProjectSettings();
        m_settings.copyTo(m_settingsCopy);
        m_testStep = new IvyDependenciesStep(m_settingsCopy, project);
    }

    public void projectOpened() {
    }

    public void projectClosed() {
    }

    @NotNull
    public String getComponentName() {
        return COMPONENT_NAME;  //To change body of implemented methods use File | Settings | File Templates.
    }

    public void initComponent() {
    }

    public void disposeComponent() {
    }

    public String getHelpTopic() {
        return "j2me.moduleJ2ME";
    }

    public Icon getIcon() {
        return BIG_ICON;
    }

    public String getDisplayName() {
        return "Ivy Project Settings";
    }

    public void apply() throws ConfigurationException {
        try {
            m_testStep.updateBuilderSettingsFromGui();
            m_settingsCopy.copyTo(m_settings);
            final UpdateModules updateModules = new UpdateModules(m_testStep.createModuleManagerFactory(m_settings), m_project);
            final ProgressUtilities.CallableToRunnableBridge<CommitInfo> res = new ProgressUtilities.CallableToRunnableBridge<CommitInfo>(updateModules);
            ProgressUtilities.runProcessWithProgressSynchronouslyNoErrorHandling(res, "Synchronising project settings...", false, null);  //don't take any locks
            //do commit outside of progress bar, to prevent facet issues...
            final CommitInfo commitInfo = res.getResult();//this may throw exception, do it outside of write action..
//            ProgressUtilities.executeAsWriteActionOnEventQueue(new ProgressAwareCallable<Object>() {
//                public Object call(ProgressIndicator indicator) throws Exception {
//                    List<ModifiableRootModel> modifiableRootModels = commitInfo.getModuleRootModels();
//                    ModifiableModuleModel modifiableModuleModel = commitInfo.getModulesModel();
//                    Set<Library.ModifiableModel> libraryModels = commitInfo.getLibraryModelsToCommit();
//                    Module[] modules = modifiableModuleModel.getModules();
//
//                    for (Module module : modules) {
//                        //don't get new model. We need the one that we want to commit..
//                        boolean found = false;
//                        for (ModifiableRootModel model : modifiableRootModels) {
//                            if (model.getModule().equals(module)) {
//                                found = true;
//                                Module[] dependencies = model.getModuleDependencies();
//                                List<String> dependentModuleNames = new LinkedList<String>();
//                                for (Module dependency : dependencies) {
//                                    dependentModuleNames.add(dependency.getName());
//                                }
//                                LOGGER.debug("Dependant modules for " + module.getName() + ": " + dependentModuleNames);
//                            }
//                        }
//                        if (!found) {
//                        LOGGER.debug("No model found to commit for " + module.getName());
//                        }
//                    }
//                    //libraries have to be committed before module model. (assert  in library.commit)
//                    for (Library.ModifiableModel libraryModel : libraryModels) {
//                        LOGGER.debug("Committing library model " + libraryModel.getName());
//                        libraryModel.commit();
//                    }
//                    //multicommit is a bit faster, but has same problem (if multiple facets are detected, exception */
//                    ProjectRootManagerImpl.getInstance(m_project).multiCommit(modifiableModuleModel, modifiableRootModels.toArray(new ModifiableRootModel[modifiableRootModels.size()]));
///*
//                    m_project.getM
//                    pair.getSecond().commit();
//                    //needed to remove unneeded modules, and add new modules.
//                    //Still, the new modules needs to be commited still.
//                    // But will do more that just that..
//                    for (ModifiableRootModel model : pair.getFirst()) {
//                        LOGGER.info("Committing module " + model.getModule().getName());
//                        model.commit();
//                    }*/
//                    return null;
//                }
//            }, null);
        } catch (ResolveException e) {
            //expected exception..
            LOGGER.debug("Unable to apply settings: " + e);
            throw new ConfigurationException(e.getLocalizedMessage());
        } catch (Exception e) {
            LOGGER.error("Unexpected exception while applying settings", e);
            throw new ConfigurationException(e.toString());
        }
        m_testStep.setModified(false);
    }

    //Ideally, only one progress window would be used for nested progress indications. This does not work however. A
    //light flicker might be seen...

    public void reset() {
        //this one is called  when ivy icon is pressed.
        try {
            m_testStep.updateGuiFromBuilderSettings();
        } catch (RuntimeException e) {
            ProgressUtilities.showException(WindowManager.getInstance().suggestParentWindow(m_project), "Unable to load settings", e);
        }
    }

    public boolean isModified() {
        return m_testStep.isModified();
    }

    public JComponent createComponent() {
        return m_testStep.getComponent();
    }


    public void disposeUIResources() {
    }
}
